package org.boulderfoodrescue.webapp.server.users;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import org.boulderfoodrescue.webapp.server.CommonDBOps;
import org.boulderfoodrescue.webapp.shared.UserAccount;
import org.boulderfoodrescue.webapp.shared.UserAccountDetails;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;

public class UserAccountsDatabase {
	private static final Logger log = Logger.getLogger(UserAccountsDatabase.class.getName());

	public static Long addUser(UserAccount user){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseUser = userAccountToEntity(user);
		Long key = datastore.put(databaseUser).getId();
		user.setDatabaseKey(key);
		log.info("Added New User to Database: "+user.getEmail());
		return key;
	}

	public static UserAccountDetails getUser(Long databaseKey){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Key key;
		key = KeyFactory.createKey("user", databaseKey);
		Entity entity;
		try {
			entity = datastore.get(key);
		} catch (EntityNotFoundException e) {
			log.warning("User was not found in the database");
			return null;
		}
		UserAccountDetails user = enityToUserAccountDetails(entity);
		return user;
	}

	public static UserAccount getUser(String email){ 
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query("user");
		query.addFilter("email", Query.FilterOperator.EQUAL, email);
		List<Entity> dUsers = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(2));
		if (dUsers.size() < 1){
			log.info("No user found with email: " + email);
			return null;
		}
		Entity dUser = dUsers.get(0);
		UserAccount user = entityToUserAccount(dUser);
		log.info("Retreived info for user: " + email);
		return user;
	}

	public static List<UserAccount> getUsers(){ 
		List<UserAccount> users = new LinkedList<UserAccount>();
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query("user");
		List<Entity> dUsers = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(1000));
		if(dUsers.size() == 1000)
		{
			log.warning("There are at least 1000 users in the database. This function will only return the first 1000 users.");
		}
		for(Entity dUser:dUsers){
			UserAccount user = entityToUserAccount(dUser);
			users.add(user);
		}
		log.info("Retrieved user info for "+users.size()+" users.");
		return users;
	}

	public static List<UserAccountDetails> getUserAccountDetails()
	{
		List<UserAccount> list = getUsers();
		List<UserAccountDetails> new_list = new LinkedList<UserAccountDetails>();
		for(UserAccount u : list)
		{
			new_list.add((UserAccountDetails) u);
		}
		return new_list;
	}

	public static String updateUser(UserAccount user){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		datastore.put(userAccountToEntity(user));
		log.info("Updated info for user: "+user.getEmail());
		return null;
	}


	public static void removeUser(UserAccount user){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseUser = new Entity("user", user.getDatabaseKey());
		datastore.delete(databaseUser.getKey());
		log.info("Deleted user: "+user.getEmail());
	}

	private static UserAccount entityToUserAccount(Entity dUser)
	{
		UserAccount user = new UserAccount();
		user.setEmail((String) dUser.getProperty("email"));
		user.setFirstName((String) dUser.getProperty("first_name"));
		user.setLastName((String) dUser.getProperty("last_name"));
		user.setAddress((String) dUser.getProperty("address"));
		user.setCity((String) dUser.getProperty("city"));
		user.setState((Long) dUser.getProperty("state"));
		user.setZipCode((String) dUser.getProperty("zip_code"));
		user.setTransportationViaLong((Long) dUser.getProperty("transportation"));
		user.setPhoneNumber((String) dUser.getProperty("phone_number"));
		user.setActivated((Boolean)dUser.getProperty("activated"));
		user.setPasscode((String) dUser.getProperty("passcode"));
		user.setAccessLevelasLong((Long) dUser.getProperty("access_level"));
		user.setDatabaseKey(dUser.getKey().getId());
		user.setAlternateEmail((String) CommonDBOps.safeProperty(dUser, "alternateEmail", null));
		user.setHasCar((Boolean) CommonDBOps.safeProperty(dUser, "hasCar", false));
		user.setNotes((String) CommonDBOps.safeProperty(dUser, "notes", ""));
		user.setPreferedContactMethodViaLong((Long) CommonDBOps.safeProperty(dUser, "preferedContactMethod", 0l));
		return user;
	}

	private static UserAccountDetails enityToUserAccountDetails(Entity dUser)
	{
		UserAccountDetails user = new UserAccount();
		user.setEmail((String) dUser.getProperty("email"));
		user.setFirstName((String) dUser.getProperty("first_name"));
		user.setLastName((String) dUser.getProperty("last_name"));
		user.setAccessLevelasLong((Long) dUser.getProperty("access_level"));
		user.setDatabaseKey(dUser.getKey().getId());
		return user;
	}

	private static Entity userAccountToEntity(UserAccount user)
	{
		Entity databaseUser;
		if(user.getDatabaseKey() != null && user.getDatabaseKey() != 0)
			databaseUser = new Entity("user", user.getDatabaseKey());
		else
			databaseUser = new Entity("user");
		databaseUser.setProperty("email", user.getEmail());
		databaseUser.setProperty("first_name", user.getFirstName());
		databaseUser.setProperty("last_name", user.getLastName());
		databaseUser.setProperty("address", user.getAddress());
		databaseUser.setProperty("city", user.getCity());
		databaseUser.setProperty("state", user.getState());
		databaseUser.setProperty("zip_code", user.getZipCode());
		databaseUser.setProperty("transportation", user.getTransportationAsLong());
		databaseUser.setProperty("phone_number", user.getPhoneNumber());
		databaseUser.setProperty("activated", true);
		databaseUser.setProperty("access_level", user.getAccessLevelasLong());
		databaseUser.setProperty("passcode", user.getPasscode());
		databaseUser.setProperty("alternateEmail", user.getAlternateEmail());
		databaseUser.setProperty("hasCar", user.getHasCar());
		databaseUser.setProperty("notes", user.getNotes());
		databaseUser.setProperty("preferedContactMethod", user.getPreferedContactMethodAsLong());
		return databaseUser;
	}
}
